package dryven.codegen.asm;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;


import dryven.codegen.asm.typeinfo.TypeInfo;

public class ArrayEntry implements Assignable, ReadableSymbol {
	
	private TypeInfo _type;
	private SubOperationListener _subOpListener;
	private int _index;
	private MethodBuilder _builder;
	
	public ArrayEntry(TypeInfo type, SubOperationListener subOpListener,
			int index, MethodBuilder builder) {
		super();
		_type = type;
		_subOpListener = subOpListener;
		_index = index;
		_builder = builder;
	}

	@Override
	public void assign(TempValue e) {
		e.checkValid();
		_subOpListener.preOperation(1);
		TempValue index = new Literal(_index, _builder).read();
		MethodVisitor mv = _builder.getMethodVisitor();
		mv.visitInsn(Opcodes.SWAP);
		storeForType(mv);
		index.pop();
		e.pop();
		_subOpListener.postOperation();
	}

	private void storeForType(MethodVisitor mv) {
		if(_type.isChar()) {
			mv.visitInsn(Opcodes.CASTORE);
		} else if(_type.isByte()) {
			mv.visitInsn(Opcodes.BASTORE);
		} else if(_type.isShort()) {
			mv.visitInsn(Opcodes.SASTORE);
		} else if(_type.isInt() || _type.isBoolean()) {
			mv.visitInsn(Opcodes.IASTORE);
		} else if(_type.isFloat()) {
			mv.visitInsn(Opcodes.FASTORE);
		} else if(_type.isDouble()) {
			mv.visitInsn(Opcodes.DASTORE);
		} else if(_type.isLong()) {
			mv.visitInsn(Opcodes.LASTORE);
		} else if(_type.isReference()) {
			mv.visitInsn(Opcodes.AASTORE);
		}
	}
	
	public void assign(ReadableSymbol e) {
		_subOpListener.preOperation(0);
		TempValue index = new Literal(_index, _builder).read();
		TempValue value = e.read();
		storeForType(_builder.getMethodVisitor());
		value.pop();
		index.pop();
		_subOpListener.postOperation();
	}

	@Override
	public TypeInfo getTypeInfo() {
		return _type;
	}

	@Override
	public TempValue read() {
		_subOpListener.preOperation(0);
		TempValue index = new Literal(_index, _builder).read();
		loadForType(_builder.getMethodVisitor());
		index.pop();
		_subOpListener.postOperation();
		return new TempValue(_type, _builder);
	}
	
	private void loadForType(MethodVisitor mv) {
		if(_type.isChar()) {
			mv.visitInsn(Opcodes.CALOAD);
		} else if(_type.isByte()) {
			mv.visitInsn(Opcodes.BALOAD);
		} else if(_type.isShort()) {
			mv.visitInsn(Opcodes.SALOAD);
		} else if(_type.isInt() || _type.isBoolean()) {
			mv.visitInsn(Opcodes.IALOAD);
		} else if(_type.isFloat()) {
			mv.visitInsn(Opcodes.FALOAD);
		} else if(_type.isDouble()) {
			mv.visitInsn(Opcodes.DALOAD);
		} else if(_type.isLong()) {
			mv.visitInsn(Opcodes.LALOAD);
		} else if(_type.isReference()) {
			mv.visitInsn(Opcodes.AALOAD);
		}
	}

}
